﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace MadProps
{
    static class PropIdCache
    {
        static Dictionary<Type, IList<PropId>> lists
            = new Dictionary<Type, IList<PropId>>();

        public static IEnumerable<PropId> GetPropIds(Type type)
        {
            type.ThrowIfNull("type");

            lock (lists)
            {
                if (!lists.ContainsKey(type))
                {
                    Build(type);
                }
            }
            return lists[type];
        }

        static void Build(Type type)
        {
            var list = new List<PropId>();

            foreach (var id in type.DeclaredProps()
                .Select(member => new PropId(member)))
            {
                list.Add(id);
            }

            var baseType = type.BaseType;
            while (baseType != null)
            {
                list.AddRange(GetPropIds(baseType));
                baseType = baseType.BaseType;
            }

            lists[type] = list.AsReadOnly();
        }

        static IEnumerable<ClrMember> DeclaredProps(this Type type)
        {
            var flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;

            return type.GetFieldsAndProperties(flags)
                .Where(member => typeof(IProp).IsAssignableFrom(member.Type));
        }
    }
}
